package com.ark.frigate.tools.utils;

import com.ark.frigate.tools.serializer.LocalDateTimeDeserializer;
import com.ark.frigate.tools.serializer.LocalDateTimeSerializer;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * Json 转化工具
 *
 * @author Along(ZengWeiLong)
 * @ClassName: JsonUtils
 * @date 2016年9月8日 下午2:26:53
 */
public class JsonUtils {

    private static Logger logger = LoggerFactory.getLogger(JsonUtils.class);

    private static ObjectMapper objectMapper;

    static {
        objectMapper = new ObjectMapper();
        // json --> pojo
        // 1.设置输入时忽略在JSON字符串中存在，但Java对象实际没有的属性
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 2.设置禁止将空对象转化到
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        // 3.按字母顺序排序属性
        /*
        objectMapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY,true);
        // 4.Json美化
        objectMapper.configure(SerializationFeature.INDENT_OUTPUT,true);
        */
        // 包含所有属性
        objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
        // 默认转化时间格式
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        // 有属性不能映射的时候不报错
        objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        // 不序列化为NULL值的Map
        objectMapper.disable(SerializationFeature.WRITE_NULL_MAP_VALUES);
        JavaTimeModule timeModule = new JavaTimeModule();
        timeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer());
        timeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer());
        objectMapper.registerModule(timeModule);
    }

    public static ObjectMapper getMapper() {

        return objectMapper;
    }

    public static synchronized void setObjectMapper(ObjectMapper objectMapper) {

        JsonUtils.objectMapper = objectMapper;
    }

    public static synchronized void setDateFormat(String dateFormat) {

        if (Objects.isNull(objectMapper)) {
            logger.error("objectMapper is null ");
        }
        objectMapper.setDateFormat(new SimpleDateFormat(dateFormat));
    }

    public static <T> T json2Object(String json, Class<T> clazz) {

        try {
            return objectMapper.readValue(json, clazz);
        } catch (Exception e) {
            throw new RuntimeJsonMappingException("解析对象错误:" + json + " to Class:" + clazz);
        }
    }

    public static <T> T json2Object(String json, TypeReference<T> type) {

        try {
            return objectMapper.readValue(json, type);
        } catch (Exception e) {
            throw new RuntimeJsonMappingException("解析对象错误:" + json + " to TypeReference Class:" + type);
        }
    }

    @SuppressWarnings("unchecked")
    public static List<Map<String, Object>> json2List(String json) {

        try {
            return objectMapper.readValue(json, List.class);
        } catch (Exception e) {
            throw new RuntimeJsonMappingException("解析对象错误:" + json + " to List");
        }
    }

    public static String toJson(Object obj) {

        try {
            return objectMapper.writeValueAsString(obj);
        } catch (Exception e) {
            throw new RuntimeJsonMappingException("解析对象错误: " + ReflectionToStringBuilder.toString(obj) + " object to jsonString");
        }
    }

    public static JsonNode parseObject(String jsonStr) {

        try {
            return objectMapper.readTree(jsonStr);
        } catch (Exception e) {
            String message = String.format("jsonString to JsonNode error;jsonString=%s", jsonStr);
            throw new RuntimeJsonMappingException(message);
        }
    }

    public static <T> List<T> json2List(String json, Class<T> clazz) {

        try {
            JavaType javaType = objectMapper.getTypeFactory().constructParametrizedType(ArrayList.class,
                    ArrayList.class, clazz);
            return objectMapper.readValue(json, javaType);
        } catch (Exception e) {
            throw new RuntimeJsonMappingException("解析对象错误:" + json + " to List");
        }
    }
}
